import mqtt from '@/plugins/mqtt.min.js'
import config from '@/config'

class MQTTClient {
	constructor() {
		// 连接状态
		this.client = null
		this.connected = false
		this.connecting = false
		this.clientId = config.mqtt.ClientIdPrefix + (config.mqtt.ClientId || Date.now().toString(36) + Math
			.random().toString(36).substr(2, 6))
		this.serverClientId = ''; // 修复逗号问题
		this.RespOpenFunc = function(data) {};
		// 订阅管理
		this.subscriptions = new Map() // <topic, {callbacks: Set, qos: number}>

		// 定时器
		this.reconnectTimer = null
		this.heartbeatTimer = null

		// 事件监听器
		this.eventListeners = {
			'connected': new Set(),
			'disconnected': new Set(),
			'message': new Set(),
			'error': new Set()
		}
	}

	/* 核心方法 */

	/**
	 * 初始化MQTT连接
	 */
	init() {
		if (this.client || this.connecting) return
		this.connecting = true
		console.log('[MQTT] clientId:', this.clientId)
		// 多端协议处理
		const protocol = this._getProtocol()
		const brokerUrl = `${protocol}://${config.mqtt.Server}:${config.mqtt.Port}${config.mqtt.Path}`

		// 连接选项
		const options = {
			clientId: this.clientId,
			username: config.mqtt.UserName,
			password: config.mqtt.Password,
			keepalive: config.mqtt.HeartbeatInterval || 60,
			clean: true,
			reconnectPeriod: 0, // 禁用自动重连
			connectTimeout: 10000
		}

		try {
			console.log('[MQTT] 正在连接:', brokerUrl)
			this.client = mqtt.connect(brokerUrl, options)
			this.GlobalSubscriptions();
			this._bindEvents()
		} catch (err) {
			console.error('[MQTT] 连接异常:', err)
			this._handleError(err)
			this._scheduleReconnect()
		}
	}

	/**
	 * 断开连接
	 */
	disconnect() {
		if (!this.client) return

		console.log('[MQTT] 正在断开连接...')
		this._clearTimers()

		try {
			this.client.end(true)
		} catch (err) {
			console.warn('[MQTT] 断开连接时异常:', err)
		} finally {
			this._cleanup()
			this._emit('disconnected')
		}
	}
	// 全局订阅
	GlobalSubscriptions(client) {
		console.log("全局订阅")
		this.subscribe((`${config.mqtt.DefaultPublishTopic}/${this.clientId}`), (msg) => {
			if (msg?.payload?.RespFunc) {
				if (msg.payload.RespFunc === "RespClientid") {
					this.serverClientId = msg.payload.Data;
					console.log("[MQTT] serverClientId：", this.serverClientId)
				} else if (msg.payload.RespFunc === "RespError") {
					console.log("[MQTT] RespError：", msg.payload)
					this.RespOpenFunc(this.deepLowerFirstKeys(msg.payload.Data.body));
				} else if (msg.payload.RespFunc === "RespOpenApi") {
					console.log("[MQTT] RespOpenApi：", msg.payload)
					this.RespOpenFunc(JSON.parse(msg.payload.Data));
				} else {
					console.warn(`[MQTT] 未注册的处理器: ${msg.payload.RespFunc}`);
				}
			}
		})
	}
	// 注册处理器（安全版）
	subscribeOpenFunc(handler) {
		if (typeof handler !== 'function') {
			throw new Error('处理器必须为函数');
		}
		this.RespOpenFunc = handler;
	}
deepLowerFirstKeys(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;
  
  if (Array.isArray(obj)) {
    return obj.map(item => this.deepLowerFirstKeys(item));
  }

  const newObj = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const newKey = key.charAt(0).toLowerCase() + key.slice(1);
      newObj[newKey] = this.deepLowerFirstKeys(obj[key]);
    }
  }
  return newObj;
}
	/* 订阅/发布 */

	/**
	 * 订阅主题
	 * @param {string} topic - 主题路径（不需要包含前缀）
	 * @param {Function} callback - 消息回调函数
	 * @param {number} [qos] - 服务质量等级（默认取配置值）
	 */
	subscribe(topic, callback, qos) {
		if (!topic || typeof callback !== 'function') return
		const finalQos = qos ?? config.mqtt.DefaultQoS ?? 1
		const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`

		// 记录订阅信息
		if (!this.subscriptions.has(topic)) {
			this.subscriptions.set(topic, {
				callbacks: new Set([callback]),
				qos: finalQos
			})
		} else {
			this.subscriptions.get(topic).callbacks.add(callback)
		}

		// 立即订阅（如果已连接）
		if (this.connected) {
			this._doSubscribe(topic, fullTopic, finalQos)
		}
	}

	/**
	 * 取消订阅
	 */
	unsubscribe(topic, callback) {
		if (!this.subscriptions.has(topic)) return

		const subscription = this.subscriptions.get(topic)

		if (callback) {
			// 移除特定回调
			subscription.callbacks.delete(callback)

			// 无回调时完全取消订阅
			if (subscription.callbacks.size === 0) {
				this._doUnsubscribe(topic)
			}
		} else {
			// 移除所有回调并取消订阅
			this._doUnsubscribe(topic)
		}
	}

	get(url, data, headers) {
		const payload = {
			data,
			headers: null,
			method: "post",
			url: `${config.baseUrl}/${url}`
		}
		this.publishOpenApi(payload);
	}
	post(url, data, headers) {
		const payload = {
			data,
			headers: null,
			method: "post",
			url: `${config.baseUrl}/${url}`
		}
		this.publishOpenApi(payload);
	}
	put(url, data, headers) {
		const payload = {
			data,
			headers: null,
			method: "put",
			url: `${config.baseUrl}/${url}`
		}
		this.publishOpenApi(payload);
	}
	delete(url, data, headers) {
		const payload = {
			data,
			headers: null,
			method: "delete",
			url: `${config.baseUrl}/${url}`
		}
		this.publishOpenApi(payload);
	}

	publishOpenApi(data) {
		const payload = {
			ClientId: this.clientId,
			Data: data,
			Func: "openapi",
			RespFunc: "RespOpenApi"
		};
		this.publish(config.mqtt.DefaultPublishTopic + "/" + this.serverClientId, payload);
	}
	publishClientId() {
		this.PublishDefaultSubscribes("clientid", "RespClientid", "publish ClientId 测试");
	}
	// 全局发布
	PublishDefaultSubscribes(func, respFunc, data) {
		const payload = {
			ClientId: this.clientId,
			Data: data,
			Func: func,
			RespFunc: respFunc
		};
		this.publish(config.mqtt.DefaultSubscribeTopics, payload);
	}

	/**
	 * 发布消息
	 */
	publish(topic, payload, qos = config.mqtt.DefaultQoS ?? 1) {
		if (!this.connected) {
			console.warn('[MQTT] 发布失败：未连接')
			return false
		}

		const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`
		const payloadStr = typeof payload === 'string' ? payload : JSON.stringify(payload)

		// 检查消息长度
		if (payloadStr.length > (config.mqtt.MaxPayloadSize ?? 268435455)) {
			console.error('[MQTT] 消息超过大小限制')
			return false
		}

		return new Promise((resolve) => {
			this.client.publish(fullTopic, payloadStr, {
				qos
			}, (err) => {
				if (err) {
					console.error('[MQTT] 发布失败:', err)
					this._emit('error', {
						type: 'publish',
						topic,
						error: err
					})
					resolve(false)
				} else {
					resolve(true)
				}
			})
		})
	}

	/* 事件管理 */

	on(event, callback) {
		if (this.eventListeners[event]) {
			this.eventListeners[event].add(callback)
		}
	}

	off(event, callback) {
		if (this.eventListeners[event]) {
			this.eventListeners[event].delete(callback)
		}
	}

	/* 私有方法 */

	_bindEvents() {
		this.client.on('connect', () => {
			console.log('[MQTT] 连接成功')
			this.connected = true
			this.connecting = false
			this._clearTimers()
			this._startHeartbeat()
			this._resubscribe()
			this._emit('connected')
			this.publishClientId()
		})

		this.client.on('error', (err) => {
			this._handleError(err)
		})

		this.client.on('close', () => {
			this._handleClose()
		})

		this.client.on('message', (topic, message) => {
			this._handleMessage(topic, message)
		})
	}

	_doSubscribe(topic, fullTopic, qos) {
		this.client.subscribe(fullTopic, {
			qos
		}, (err) => {
			if (err) {
				console.error(`[MQTT] 订阅失败 [${fullTopic}]:`, err)
				this._emit('error', {
					type: 'subscribe',
					topic,
					error: err
				})
			}
		})
	}

	_doUnsubscribe(topic) {
		const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`
		if (this.connected) {
			this.client.unsubscribe(fullTopic, (err) => {
				if (err) {
					console.error(`[MQTT] 取消订阅失败 [${fullTopic}]:`, err)
				}
			})
		}
		this.subscriptions.delete(topic)
	}

	_handleMessage(topic, message) {
		try {
			// 消息解析（兼容多端）
			let payload
			if (message instanceof ArrayBuffer) {
				payload = new TextDecoder('utf-8').decode(new Uint8Array(message))
			} else {
				payload = message.toString()
			}

			try {
				payload = JSON.parse(payload)
			} catch (e) {
				// 非JSON数据保持原样
			}

			// 提取短主题名
			const fullPrefix = `${config.mqtt.TopicPrefix}/`
			const shortTopic = topic.startsWith(fullPrefix) ?
				topic.substring(fullPrefix.length) :
				topic

			// 触发消息事件
			const messageData = {
				fullTopic: topic,
				shortTopic,
				payload
			}

			// 触发特定主题回调
			if (this.subscriptions.has(shortTopic)) {
				const {
					callbacks
				} = this.subscriptions.get(shortTopic)
				callbacks.forEach(cb => cb(messageData))
			}

			// 触发全局消息事件
			this._emit('message', messageData)

		} catch (err) {
			console.error('[MQTT] 消息处理异常:', err)
			this._emit('error', {
				type: 'message',
				error: err
			})
		}
	}

	_handleError(err) {
		console.error('[MQTT] 连接错误:', err)
		this._cleanup()
		this._emit('error', {
			type: 'connection',
			error: err
		})
		this._scheduleReconnect()
	}

	_handleClose() {
		console.log('[MQTT] 连接已关闭')
		this._cleanup()
		this._emit('disconnected')
		this._scheduleReconnect()
	}

	_scheduleReconnect() {
		this._clearTimers()

		console.log('[MQTT] 10秒后尝试重连')
		this.reconnectTimer = setTimeout(() => {
			this.init()
		}, 10000)
	}

	_resubscribe() {
		if (this.subscriptions.size === 0) return

		console.log('[MQTT] 恢复订阅...')
		this.subscriptions.forEach((sub, topic) => {
			const fullTopic = `${config.mqtt.TopicPrefix}/${topic}`
			this._doSubscribe(topic, fullTopic, sub.qos)
		})
	}

	_startHeartbeat() {
		this._stopHeartbeat()

		const interval = (config.mqtt.HeartbeatInterval || 60) * 1000
		this.heartbeatTimer = setInterval(() => {
			if (this.connected) {
				this.publish(
					config.mqtt.DefaultPublishTopic || 'heartbeat', {
						type: 'heartbeat',
						clientId: this.clientId,
						timestamp: Date.now()
					},
					0 // QoS 0
				).catch(console.error)
			}
		}, interval)
	}

	_stopHeartbeat() {
		if (this.heartbeatTimer) {
			clearInterval(this.heartbeatTimer)
			this.heartbeatTimer = null
		}
	}

	_cleanup() {
		this.connected = false
		this.connecting = false

		if (this.client) {
			this.client.removeAllListeners()
			this.client = null
		}

		this._clearTimers()
	}

	_clearTimers() {
		this._stopHeartbeat()

		if (this.reconnectTimer) {
			clearTimeout(this.reconnectTimer)
			this.reconnectTimer = null
		}
	}

	_emit(event, data) {
		if (this.eventListeners[event]) {
			this.eventListeners[event].forEach(cb => cb(data))
		}
	}

	_getProtocol() {
		// #ifdef MP-WEIXIN
		return 'wxs'
		// #endif
		// #ifdef APP-PLUS
		return 'tcp'
		// #endif
		return 'ws'
	}
}

// 导出单例
const mqttInstance = new MQTTClient()
export default mqttInstance